﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

namespace Mr.LinqToWeibo.SearchCriteria
{
	internal class SearchCriteriaCreator : ExpressionVisitor
	{
		private Expression expression;
		private ISearchCriteria criteria;
		private bool baseAppNot;
		private bool baseAppSet;

		public SearchCriteriaCreator (Expression exp)
		{
			this.expression = exp;
		}

		public ISearchCriteria Criteria {
			get {
				if (this.criteria == null) {
					this.criteria = new SearchCriteriaImpl ();
					this.Visit (this.expression);
				}
				return this.criteria;
			}
		}

		protected override Expression VisitMethodCall (MethodCallExpression m)
		{
			if (m.Method.Name == "Take") {
				this.criteria.Count = Convert.ToInt32 (((ConstantExpression)m.Arguments [1]).Value);
			} else if (m.Method.Name == "Skip") {
				this.criteria.PageIndex = Convert.ToInt32 (((ConstantExpression)m.Arguments [1]).Value) + 1;
			}

			return base.VisitMethodCall (m);
		}
		
		protected override Expression VisitUnary (UnaryExpression u)
		{
			if (u.NodeType == ExpressionType.Not) {
				if (u.Operand is MemberExpression && 
					((MemberExpression)(u.Operand)).Member.Name == "BaseApp") {
					this.baseAppNot = true;
					this.criteria.BaseApp = this.baseAppSet ? !this.criteria.BaseApp : false;
				}
			}
			return base.VisitUnary (u);
		}
		
		protected override Expression VisitMemberAccess (MemberExpression m)
		{
			if (m.Type.Name == "Boolean") {
				if (m.Member.Name == "BaseApp") {
					if (!this.baseAppSet) {
						this.criteria.BaseApp = this.baseAppNot ? false : true;
					} 
				}
			}
			return base.VisitMemberAccess (m);
		}
		
		protected override Expression VisitBinary (BinaryExpression be)
		{
			MemberExpression memberExpression = ExpressionTreeHelpers.GetRootParameterMemberExpression (be);
			
			if (memberExpression != null) {
				string name = memberExpression.Member.Name;
				object beValue = ExpressionTreeHelpers.GetValFromExpression (be);
				if (name == "Id") {
					long number = Convert.ToInt64 (beValue);
					if (memberExpression.Expression is MemberExpression) {
						string memberName = ((MemberExpression)(memberExpression.Expression)).Member.Name;
						if (memberName == "User") {
							this.criteria.UserId = number;
						} else if (memberName == "Weibo") {
							this.criteria.Id = number;
						}
					} else {						
						if (be.NodeType == ExpressionType.Equal) {
							if (this.criteria.Id == 0) {
								this.criteria.Id = number;
							}
						} else if (be.NodeType == ExpressionType.GreaterThanOrEqual) {
							if (this.criteria.SinceId == 0 || number > this.criteria.SinceId) {
								this.criteria.SinceId = number;
							}
						} else if (be.NodeType == ExpressionType.LessThanOrEqual) {
							if (this.criteria.MaxId == 0 || number < this.criteria.MaxId) {
								this.criteria.MaxId = number;
							}
						}
					}
				} else if (name == "KeyWord" && be.NodeType == ExpressionType.Equal) {
					this.criteria.TrendKeyWord = beValue.ToString ();
				} else if (name == "Feature" && be.NodeType == ExpressionType.Equal) {
					this.criteria.Feature = (Feature)Convert.ToInt16 (beValue);
				} else if (name == "BaseApp" && be.NodeType == ExpressionType.Equal) {
					this.baseAppSet = true;
					this.criteria.BaseApp = Convert.ToBoolean (beValue);
				}
			}

			return base.VisitBinary (be);
		}
	}
}
